/*-------------------------------------------------------------------------
 *
 * transam.h
 *	  PostgreSQL 事务访问方法支持代码
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/transam.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef TRANSAM_H
#define TRANSAM_H

#include "access/xlogdefs.h"


/* ----------------
 *		特殊事务 ID 值
 *
 * BootstrapTransactionId 是“引导”操作的 XID，FrozenTransactionId 用于非常旧的元组。两个值应
 * 始终被视为有效。
 *
 * FirstNormalTransactionId 是第一个“正常”事务 ID。
 * 注意：如果您需要更改它，您必须同时更改 pg_class.h。
 * ----------------
 */
#define InvalidTransactionId		((TransactionId) 0)
#define BootstrapTransactionId		((TransactionId) 1)
#define FrozenTransactionId			((TransactionId) 2)
#define FirstNormalTransactionId	((TransactionId) 3)
#define MaxTransactionId			((TransactionId) 0xFFFFFFFF)

/* ----------------
 *		事务 ID 操作宏
 * ----------------
 */
#define TransactionIdIsValid(xid)		((xid) != InvalidTransactionId)
#define TransactionIdIsNormal(xid)		((xid) >= FirstNormalTransactionId)
#define TransactionIdEquals(id1, id2)	((id1) == (id2))
#define TransactionIdStore(xid, dest)	(*(dest) = (xid))
#define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId)

#define EpochFromFullTransactionId(x)	((uint32) ((x).value >> 32))
#define XidFromFullTransactionId(x)		((uint32) (x).value)
#define U64FromFullTransactionId(x)		((x).value)
#define FullTransactionIdEquals(a, b)	((a).value == (b).value)
#define FullTransactionIdPrecedes(a, b)	((a).value < (b).value)
#define FullTransactionIdPrecedesOrEquals(a, b) ((a).value <= (b).value)
#define FullTransactionIdFollows(a, b) ((a).value > (b).value)
#define FullTransactionIdFollowsOrEquals(a, b) ((a).value >= (b).value)
#define FullTransactionIdIsValid(x)		TransactionIdIsValid(XidFromFullTransactionId(x))
#define InvalidFullTransactionId		FullTransactionIdFromEpochAndXid(0, InvalidTransactionId)
#define FirstNormalFullTransactionId	FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId)
#define FullTransactionIdIsNormal(x)	FullTransactionIdFollowsOrEquals(x, FirstNormalFullTransactionId)

/*
 * 一个包含一个纪元和一个 TransactionId 的 64 位值。这是
 * 封装在一个结构中以防止隐式转换为/从 TransactionId。
 * 并非所有值都代表有效的正常 XIDs。
 */
typedef struct FullTransactionId
{
	uint64		value;
} FullTransactionId;

static inline FullTransactionId
FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
{
	FullTransactionId result;

	result.value = ((uint64) epoch) << 32 | xid;

	return result;
}

static inline FullTransactionId
FullTransactionIdFromU64(uint64 value)
{
	FullTransactionId result;

	result.value = value;

	return result;
}

/* 前进一个事务 ID 变量，正确处理环绕 */
#define TransactionIdAdvance(dest)	\
	do { \
		(dest)++; \
		if ((dest) < FirstNormalTransactionId) \
			(dest) = FirstNormalTransactionId; \
	} while(0)

/*
 * 撤回 FullTransactionId 变量，跳过只在
 * 视为 32 位 XIDs 时才会显得特别的 xids。
 */
static inline void
FullTransactionIdRetreat(FullTransactionId *dest)
{
	dest->value--;

	/*
	 * 与 32 位 XIDs 不同，不要跳过“实际的”特殊 xids。
	 * 对于 64 位 xids，这些在环绕过程中无法到达，正如在 32 位情况下那样。
	 */
	if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId))
		return;

	
/*
	 * 但我们确实需要跳过那些在32位XIDs中看起来特殊的XIDs。
	 */
	while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId)
		dest->value--;
}

/*
 * 增加一个FullTransactionId变量，跳过在作为32位XIDs查看时看起来特殊的xids。
 */
static inline void
FullTransactionIdAdvance(FullTransactionId *dest)
{
	dest->value++;

	/* 参见FullTransactionIdAdvance() */
	if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId))
		return;

	while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId)
		dest->value++;
}

/* 备份事务 ID 变量，正确处理换卷 */
#define TransactionIdRetreat(dest)	\
	do { \
		(dest)--; \
	} while ((dest) < FirstNormalTransactionId)

/* 比较两个已知正常的 XID；这是一个宏以提高速度 */
#define NormalTransactionIdPrecedes(id1, id2) \
	(AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \
	(int32) ((id1) - (id2)) < 0)

/* 比较两个已知正常的 XID；这是一个宏以提高速度 */
#define NormalTransactionIdFollows(id1, id2) \
	(AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \
	(int32) ((id1) - (id2)) > 0)

/* ----------
 *		Object ID (OID) 零是 InvalidOid。
 *
 *		OIDs 1-9999 保留用于手动分配（见 src/include/catalog/ 中
 *		的 .dat 文件）。其中，8000-9999 保留用于开发目的
 *		（如进行中的补丁和分叉）；它们不应出现在已发布的版本中。
 *
 *		OIDs 10000-11999 保留用于 genbki.pl 分配，用于
 *		当 src/include/catalog/ 中的 .dat 文件未指定需要 OID 的
 *		目录条目时。注意，genbki.pl 在每个目录中独立分配
 *		这些 OIDs，因此它们不能保证全局唯一。此外，bootstrap backend 和
 *		initdb 的后引导处理也可以在此范围内分配 OIDs。
 *		正常的 OID 生成逻辑会处理可能因这些因素而产生的任何 OID 冲突。
 *
 *		OIDs 12000-16383 保留用于 initdb 的后引导处理创建的
 *		未固定对象。initdb 在负责固定对象后立即将 OID 生成器
 *		提高到 12000。
 *
 *		以 16384 开头的 OIDs 在正常多用户操作期间从 OID 生成器
 *		中分配。（我们在正常操作时将生成器立即提高到 16384。）
 *
 * 选择 8000、10000 和 12000 是完全任意的，如果我们在任何类别中 OID 用尽，
 * 可以移动这些值。改变下面的宏，并更新相关文档（见 bki.sgml 和 RELEASE_CHANGES），
 * 应该足以做到这一点。然而，移动 initdb 分配的 OIDs 和用户定义对象之间的 16384 边界
 * 将会更加痛苦，因为某些用户定义的 OIDs 将出现在磁盘数据中；这样的更改可能会破坏
 * pg_upgrade。
 *
 * 注意：如果 OID 生成器换卷，我们将跳过 OIDs 0-16383
 * 并从 16384 继续。这可以通过不重新分配在 initdb 期间可能已经分配的 OIDs，
 * 从而最小化 OID 冲突的几率。至关重要的是，它还确保没有用户创建的对象会被视为固定。
 * ----------
 */
#define FirstGenbkiObjectId		10000
#define FirstUnpinnedObjectId	12000
#define FirstNormalObjectId		16384

/*
 * VariableCache 是一个存储在共享内存中的数据结构，用于跟踪
 * OID 和 XID 分配状态。由于历史原因，只有一个结构，其中的不同字段
 * 受到不同 LWLocks 的保护。
 *
 * 注意：xidWrapLimit 和 oldestXidDB 不是“活动”值，而只是
 * 用于生成有用信息，以便当超过 xidWarnLimit 或 xidStopLimit 时发出警告。
 */
typedef struct VariableCacheData
{
	/*
	 * 这些字段受到 OidGenLock 保护。
	 */
	Oid			nextOid;		/* 下一个要分配的 OID */
	uint32		oidCount;		/* 必须执行 XLOG 工作的可用 OIDs */

	/*
	 * 这些字段由 XidGenLock 保护。
	 */
	FullTransactionId nextXid;	/* 下一个分配的 XID */

	TransactionId oldestXid;	/* 集群范围内的最小 datfrozenxid */
	TransactionId xidVacLimit;	/* 在这里开始强制自动清理 */
	TransactionId xidWarnLimit; /* 在这里开始抱怨 */
	TransactionId xidStopLimit; /* 拒绝在这里推进 nextXid */
	TransactionId xidWrapLimit; /* 世界结束的地方 */
	Oid			oldestXidDB;	/* 具有最小 datfrozenxid 的数据库 */

	/*
	 * 这些字段受到 CommitTsLock 的保护
	 */
	TransactionId oldestCommitTsXid;
	TransactionId newestCommitTsXid;

	/*
	 * 这些字段受到 ProcArrayLock 的保护。
	 */
	FullTransactionId latestCompletedXid;	/* 最新的完整 XID
											 * 已提交或中止 */

	/*
	 * 自服务器启动以来以某种形式完成的顶级事务数（即可能
	 * 修改了数据库的事务）。这目前仅用于检查
	 * GetSnapshotData() 是否需要重新计算快照的内容。
	 * 可能还有其他使用者。始终大于 1。
	 */
	uint64		xactCompletionCount;

	/*
	 * 这些字段受到 XactTruncationLock 的保护
	 */
	TransactionId oldestClogXid;	/* 在 clog 中查找的最古老的安全值 */

} VariableCacheData;

typedef VariableCacheData *VariableCache;


/* ----------------
 *		外部声明
 * ----------------
 */

/* 在 transam/xact.c 中 */
extern bool TransactionStartedDuringRecovery(void);

/* 在 transam/varsup.c 中 */
extern PGDLLIMPORT VariableCache ShmemVariableCache;

/*
 * transam/transam.c 中函数的原型
 */
extern bool TransactionIdDidCommit(TransactionId transactionId);
extern bool TransactionIdDidAbort(TransactionId transactionId);
extern void TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids);
extern void TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn);
extern void TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids);
extern bool TransactionIdPrecedes(TransactionId id1, TransactionId id2);
extern bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2);
extern bool TransactionIdFollows(TransactionId id1, TransactionId id2);
extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2);
extern TransactionId TransactionIdLatest(TransactionId mainxid,
										 int nxids, const TransactionId *xids);
extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid);

/* 在 transam/varsup.c 中 */
extern FullTransactionId GetNewTransactionId(bool isSubXact);
extern void AdvanceNextFullTransactionIdPastXid(TransactionId xid);
extern FullTransactionId ReadNextFullTransactionId(void);
extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
								  Oid oldest_datoid);
extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid);
extern bool ForceTransactionIdLimitUpdate(void);
extern Oid	GetNewObjectId(void);
extern void StopGeneratingPinnedObjectIds(void);

#ifdef USE_ASSERT_CHECKING
extern void AssertTransactionIdInAllowableRange(TransactionId xid);
#else
#define AssertTransactionIdInAllowableRange(xid) ((void)true)
#endif

/*
 * 一些前端程序包含此头文件。对于即使未使用
 * 也会生成静态内联函数的编译器，这会导致未满足的
 * 外部引用；因此使用 #ifndef FRONTEND 隐藏它们。
 */
#ifndef FRONTEND

/*
 * 对于只需要下一个事务 ID 的 XID 部分的调用者。
 */
static inline TransactionId
ReadNextTransactionId(void)
{
	return XidFromFullTransactionId(ReadNextFullTransactionId());
}

/* 返回由 amount 支持的事务 ID，正确处理环绕 */
static inline TransactionId
TransactionIdRetreatedBy(TransactionId xid, uint32 amount)
{
	xid -= amount;

	while (xid < FirstNormalTransactionId)
		xid--;

	return xid;
}

/* 返回两个 ID 中的较旧者 */
static inline TransactionId
TransactionIdOlder(TransactionId a, TransactionId b)
{
	if (!TransactionIdIsValid(a))
		return b;

	if (!TransactionIdIsValid(b))
		return a;

	if (TransactionIdPrecedes(a, b))
		return a;
	return b;
}

/* 返回两个 ID 中较旧的一个，假设它们都是正常的 */
static inline TransactionId
NormalTransactionIdOlder(TransactionId a, TransactionId b)
{
	Assert(TransactionIdIsNormal(a));
	Assert(TransactionIdIsNormal(b));
	if (NormalTransactionIdPrecedes(a, b))
		return a;
	return b;
}

/* 返回两个 ID 中较新的一个 */
static inline FullTransactionId
FullTransactionIdNewer(FullTransactionId a, FullTransactionId b)
{
	if (!FullTransactionIdIsValid(a))
		return b;

	if (!FullTransactionIdIsValid(b))
		return a;

	if (FullTransactionIdFollows(a, b))
		return a;
	return b;
}

#endif							/* FRONTEND */

#endif							/* TRANSAM_H */
